int planResearch(int tech = -1, int escrow = cRootEscrowID, int building = -1)
{
    if (kbTechGetStatus(tech) == cTechStatusActive)
        return(-1);
    if (aiPlanGetIDByTypeAndVariableType(cPlanResearch, cResearchPlanTechID, tech, true) >= 0)
        return(-1);
    int plan = aiPlanCreate("Research "+kbGetTechName(tech), cPlanResearch);
    aiPlanSetEscrowID(plan, escrow);
    aiPlanSetVariableInt(plan, cResearchPlanTechID, 0, tech);
    aiPlanSetVariableInt(plan, cResearchPlanBuildingID, 0, building);
    aiPlanSetActive(plan, true);
    return(plan);
}


int planMaintain(int unit = -1, int number = 1, int escrow = cRootEscrowID, int batch = 1, int building = -1, int maxqueue = 1, bool multibuildings = false)
{
    int plan = aiPlanCreate("Maintain "+kbGetProtoUnitName(unit), cPlanTrain);
    aiPlanSetEscrowID(plan, escrow);
    aiPlanSetVariableInt(plan, cTrainPlanUnitType, 0, unit);
    aiPlanSetVariableInt(plan, cTrainPlanNumberToMaintain, 0, number);
    aiPlanSetVariableInt(plan, cTrainPlanBatchSize, 0, batch);
    aiPlanSetVariableInt(plan, cTrainPlanBuildFromType, 0, building);
    aiPlanSetVariableInt(plan, cTrainPlanMaxQueueSize, 0, maxqueue);
    aiPlanSetVariableBool(plan, cTrainPlanUseMultipleBuildings, 0, multibuildings);
    aiPlanSetActive(plan, true);
    return(plan);
}


int planMaintainAt(int unit = -1, int number = 1, int escrow = cRootEscrowID, int batch = 1, int building = -1, int maxqueue = 1)
{
    int plan = aiPlanCreate("Maintain (specific) "+kbGetProtoUnitName(unit), cPlanTrain);
    aiPlanSetEscrowID(plan, escrow);
    aiPlanSetVariableInt(plan, cTrainPlanUnitType, 0, unit);
    aiPlanSetVariableInt(plan, cTrainPlanNumberToMaintain, 0, number);
    aiPlanSetVariableInt(plan, cTrainPlanBatchSize, 0, batch);
    aiPlanSetVariableInt(plan, cTrainPlanBuildFromType, 0, building);
    aiPlanSetVariableInt(plan, cTrainPlanMaxQueueSize, 0, maxqueue);
    aiPlanSetVariableBool(plan, cTrainPlanUseMultipleBuildings, 0, false);
    aiPlanSetActive(plan, true);
    return(plan);
}


int planBuild(int building = -1, int base = -1, int builder = -1, int num_builders = 1, int pri = 50, int escrow = cRootEscrowID, float buffer = 5.0)
{
    int plan = aiPlanCreate("Build "+kbGetProtoUnitName(building), cPlanBuild);
    aiPlanSetDesiredPriority(plan, pri);
    aiPlanSetEscrowID(plan, escrow);
    aiPlanSetBaseID(plan, base);
    aiPlanSetEconomy(plan, (kbProtoUnitIsType(cMyID, building, cUnitTypeCountsTowardEconomicScore) == true));
    aiPlanSetMilitary(plan, (kbProtoUnitIsType(cMyID, building, cUnitTypeCountsTowardEconomicScore) == false));
    
    aiPlanSetVariableInt(plan, cBuildPlanBuildingTypeID, 0, building);
    aiPlanSetVariableFloat(plan, cBuildPlanBuildingBufferSpace, 0, buffer);
    
    aiPlanSetNumberVariableValues(plan, cBuildPlanInfluenceUnitTypeID, 2, true);
    aiPlanSetNumberVariableValues(plan, cBuildPlanInfluenceUnitDistance, 2, true);
    aiPlanSetNumberVariableValues(plan, cBuildPlanInfluenceUnitValue, 2, true);
    aiPlanSetNumberVariableValues(plan, cBuildPlanInfluenceUnitFalloff, 2, true);
    
    aiPlanSetVariableInt(plan, cBuildPlanInfluenceUnitTypeID, 0, cUnitTypeHomeCityWaterSpawnFlag);
    aiPlanSetVariableFloat(plan, cBuildPlanInfluenceUnitDistance, 0, 50.0);
    aiPlanSetVariableFloat(plan, cBuildPlanInfluenceUnitValue, 0, -500.0);
    aiPlanSetVariableInt(plan, cBuildPlanInfluenceUnitFalloff, 0, cBPIFalloffLinearInverse);
    
    aiPlanSetVariableInt(plan, cBuildPlanInfluenceUnitTypeID, 1, cUnitTypeMaoriPa);
    aiPlanSetVariableFloat(plan, cBuildPlanInfluenceUnitDistance, 1, 30.0);
    aiPlanSetVariableFloat(plan, cBuildPlanInfluenceUnitValue, 1, -500.0);
    aiPlanSetVariableInt(plan, cBuildPlanInfluenceUnitFalloff, 1, cBPIFalloffLinearInverse);
    
    aiPlanAddUnitType(plan, builder, num_builders, num_builders, num_builders);
    
    aiPlanSetActive(plan, true);
    return(plan);
}


int planBuildAt(int building = -1, vector location = cInvalidVector, int builder = -1, int num_builders = 1, int pri = 50, int escrow = cRootEscrowID)
{
    int plan = aiPlanCreate("Build (loc) "+kbGetProtoUnitName(building), cPlanBuild);
    aiPlanSetDesiredPriority(plan, pri);
    aiPlanSetEscrowID(plan, escrow);
    aiPlanSetEconomy(plan, (kbProtoUnitIsType(cMyID, building, cUnitTypeCountsTowardEconomicScore) == true));
    aiPlanSetMilitary(plan, (kbProtoUnitIsType(cMyID, building, cUnitTypeCountsTowardEconomicScore) == false));
    
    aiPlanSetVariableInt(plan, cBuildPlanBuildingTypeID, 0, building);
    aiPlanSetVariableVector(plan, cBuildPlanCenterPosition, 0, location);
    aiPlanSetVariableFloat(plan, cBuildPlanCenterPositionDistance, 0, 300.0);
    aiPlanSetVariableFloat(plan, cBuildPlanBuildingBufferSpace, 0, 5.0);
    
    aiPlanSetVariableVector(plan, cBuildPlanInfluencePosition, 0, location);
    aiPlanSetVariableFloat(plan, cBuildPlanInfluencePositionDistance, 0, 100.0);
    aiPlanSetVariableFloat(plan, cBuildPlanInfluencePositionValue, 0, 200.0);
    aiPlanSetVariableInt(plan, cBuildPlanInfluencePositionFalloff, 0, cBPIFalloffLinear);
    
    if (xsVectorLength(location - kbBaseGetLocation(cMyID, kbBaseGetMainID(cMyID))) < 31.0)
    {
        aiPlanSetVariableInt(plan, cBuildPlanInfluenceUnitTypeID, 0, cUnitTypeMaoriPa);
        aiPlanSetVariableFloat(plan, cBuildPlanInfluenceUnitDistance, 0, 30.0);
        aiPlanSetVariableFloat(plan, cBuildPlanInfluenceUnitValue, 0, -500.0);
        aiPlanSetVariableInt(plan, cBuildPlanInfluenceUnitFalloff, 0, cBPIFalloffLinearInverse);
    }
    
    int hcFlag = findUnit1(cUnitTypeHomeCityWaterSpawnFlag, cMyID, 0);
    if ((hcFlag >= 0) && (xsVectorLength(location - kbUnitGetPosition(hcFlag)) < 50.0))
    {
        aiPlanSetNumberVariableValues(plan, cBuildPlanInfluenceUnitTypeID, 2, false);
        aiPlanSetNumberVariableValues(plan, cBuildPlanInfluenceUnitDistance, 2, false);
        aiPlanSetNumberVariableValues(plan, cBuildPlanInfluenceUnitValue, 2, false);
        aiPlanSetNumberVariableValues(plan, cBuildPlanInfluenceUnitFalloff, 2, false);
        
        aiPlanSetVariableInt(plan, cBuildPlanInfluenceUnitTypeID, 1, cUnitTypeMaoriPa);
        aiPlanSetVariableFloat(plan, cBuildPlanInfluenceUnitDistance, 1, 30.0);
        aiPlanSetVariableFloat(plan, cBuildPlanInfluenceUnitValue, 1, -500.0);
        aiPlanSetVariableInt(plan, cBuildPlanInfluenceUnitFalloff, 1, cBPIFalloffLinearInverse);
    }
    
    aiPlanAddUnitType(plan, builder, num_builders, num_builders, num_builders);
    
    aiPlanSetActive(plan, true);
    return(plan);
}


int planBuildFarFromEachOther(int building = -1, vector center = cInvalidVector, int builder = -1, int num_builders = 1, int escrow = cRootEscrowID, int pri = 50)
{
    int plan = aiPlanCreate("Build "+kbGetProtoUnitName(building), cPlanBuild);
    aiPlanSetDesiredPriority(plan, pri);
    aiPlanSetEconomy(plan, (kbProtoUnitIsType(cMyID, building, cUnitTypeCountsTowardEconomicScore) == true));
    aiPlanSetMilitary(plan, (kbProtoUnitIsType(cMyID, building, cUnitTypeCountsTowardEconomicScore) == false));
    aiPlanSetEscrowID(plan, escrow);
    
    aiPlanSetVariableInt(plan, cBuildPlanBuildingTypeID, 0, building);
    
    aiPlanSetVariableVector(plan, cBuildPlanCenterPosition, 0, center);
    aiPlanSetVariableFloat(plan, cBuildPlanCenterPositionDistance, 0, 100.0);
    
    aiPlanSetNumberVariableValues(plan, cBuildPlanInfluenceUnitTypeID, 4, true);
    aiPlanSetNumberVariableValues(plan, cBuildPlanInfluenceUnitDistance, 4, true);
    aiPlanSetNumberVariableValues(plan, cBuildPlanInfluenceUnitValue, 4, true);
    aiPlanSetNumberVariableValues(plan, cBuildPlanInfluenceUnitFalloff, 4, true);
    
    aiPlanSetVariableInt(plan, cBuildPlanInfluenceUnitTypeID, 0, cUnitTypeWood);
    aiPlanSetVariableFloat(plan, cBuildPlanInfluenceUnitDistance, 0, 30.0);
    aiPlanSetVariableFloat(plan, cBuildPlanInfluenceUnitValue, 0, 10.0);
    aiPlanSetVariableInt(plan, cBuildPlanInfluenceUnitFalloff, 0, cBPIFalloffLinear);
    
    aiPlanSetVariableInt(plan, cBuildPlanInfluenceUnitTypeID, 1, cUnitTypeMine);
    aiPlanSetVariableFloat(plan, cBuildPlanInfluenceUnitDistance, 1, 40.0);
    aiPlanSetVariableFloat(plan, cBuildPlanInfluenceUnitValue, 1, 300.0);
    aiPlanSetVariableInt(plan, cBuildPlanInfluenceUnitFalloff, 1, cBPIFalloffLinear);
    
    aiPlanSetVariableInt(plan, cBuildPlanInfluenceUnitTypeID, 2, cUnitTypeMine);
    aiPlanSetVariableFloat(plan, cBuildPlanInfluenceUnitDistance, 2, 10.0);
    aiPlanSetVariableFloat(plan, cBuildPlanInfluenceUnitValue, 2, -300.0);
    aiPlanSetVariableInt(plan, cBuildPlanInfluenceUnitFalloff, 2, cBPIFalloffNone);
    
    aiPlanSetVariableInt(plan, cBuildPlanInfluenceUnitTypeID, 0, building);
    aiPlanSetVariableFloat(plan, cBuildPlanInfluenceUnitDistance, 0, 40.0);
    aiPlanSetVariableFloat(plan, cBuildPlanInfluenceUnitValue, 0, -500.0);
    aiPlanSetVariableInt(plan, cBuildPlanInfluenceUnitFalloff, 0, cBPIFalloffNone);
    
    aiPlanSetVariableVector(plan, cBuildPlanInfluencePosition, 0, center);
    aiPlanSetVariableFloat(plan, cBuildPlanInfluencePositionDistance, 0, 100.0);
    aiPlanSetVariableFloat(plan, cBuildPlanInfluencePositionValue, 0, 300.0);
    aiPlanSetVariableInt(plan, cBuildPlanInfluencePositionFalloff, 0, cBPIFalloffLinear);
    
    aiPlanAddUnitType(plan, builder, num_builders, num_builders, num_builders);
    
    aiPlanSetActive(plan, true);
    
    return(plan);
}

